package cn.itsource.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.IdUtil;
import cn.itsource.api.openfeign.ILoginOpenfeignClient;
import cn.itsource.constants.CacheConstants;
import cn.itsource.constants.ErrorCode;
import cn.itsource.constants.MQconstans;
import cn.itsource.constants.RConst;
import cn.itsource.exception.GlobalException;
import cn.itsource.pojo.domain.*;
import cn.itsource.mapper.DriverMapper;

import cn.itsource.pojo.dto.PushOrder;
import cn.itsource.pojo.dto.RegisterDto;
import cn.itsource.pojo.ro.DriverOnLineRo;
import cn.itsource.pojo.ro.GeoRo;
import cn.itsource.pojo.ro.LoginRo;
import cn.itsource.pojo.ro.WxChatRegisterRo;
import cn.itsource.result.JSONResult;
import cn.itsource.service.*;
import cn.itsource.utils.NameUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;


import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
import org.apache.rocketmq.client.consumer.PullResult;
import org.apache.rocketmq.client.consumer.PullStatus;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.message.MessageQueue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 司机对象 服务实现类
 * </p>
 *
 * @author whale
 * @since 2024-07-02
 */
@Service
@Slf4j
public class DriverServiceImpl extends ServiceImpl<DriverMapper, Driver> implements IDriverService {
    @Autowired
    private IDriverAggrementService driverAggrementService;

    @Autowired
    private WechatService weChatService;
    @Autowired
    private ILoginOpenfeignClient iLoginOpenfeignClient;
    @Autowired
    private IDriverSummaryService driverSummaryService;
    @Autowired
    private IDriverSettingService driverSettingService;
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    private DefaultMQPullConsumer pullConsumer;


   /* private String appid = "wxb434d560e93a18f5";
    private String AppSecret = "c8cbc866ac3e3e471b1fcda9f31ef5c0";
    private String code2SessionUrl =
            "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";*/
    /**
     * 实现业务逻辑
     * @param registerRo
     * @return
     */
    @Override
    @Transactional
/*   @GlobalTransactional*/

    public JSONResult wxChatRegister(WxChatRegisterRo registerRo) {
     /*   log.info(registerRo.getCode());
        //拼接请求地址
        String sendUrl = String.format(Constants.Driver.CODE_2_SESSION_URL, wxConfig.getAppid(), wxConfig.getAppSecret(),registerRo.getCode());
        log.info(sendUrl);//打印日志只需要打印核心
       //发送请求 用的huto工具包
        String result = HttpUtil.get(sendUrl);//返回的是json字符串
      //江json字符串转为对象
        RegisterDto registerDto = JSONObject.parseObject(result, RegisterDto.class);
        log.info("这是我想要的id"+registerDto);*/
        //新增司机表和合同表的方法
        //先判断是不是已经存在了 如果已经存在了 那么就不保存
        RegisterDto registerDto = weChatService.getWechatOpenId(registerRo.getCode());
        Driver one = super.getOne(new LambdaQueryWrapper<Driver>().eq(Driver::getOpenId, registerDto.getOpenid()));
        if(one == null){
            Long id = initDriver(registerDto);
            iLoginOpenfeignClient.createLogin(buildLoginRo(registerDto,id));
           /* int i = 1/0;*/
            return JSONResult.message("微信绑定成功");
        }
        return JSONResult.error(ErrorCode.WE_CHAT_REPEAT_ERROR);
    }

    @Override
    public DriverSetting driverOnLine(DriverOnLineRo onLineRo) {
        //干什么事情？
        String openId = StpUtil.getExtra("openId").toString();
        Driver one = super.getOne(new LambdaQueryWrapper<Driver>().eq(Driver::getOpenId, openId));
        //注意一个司机只有一个配置  初始化就有
        DriverSetting setting = driverSettingService.getById(one.getId());
        //将我们的司机的配置缓存到redis里面
        String key = String.format(CacheConstants.KEY_DRIVER_ONLINE_SETTING, one.getId());
        redisTemplate.opsForValue()
                .set(key,setting,RConst.Num.INT_5, TimeUnit.MINUTES);
        //坐标记录到redis 里面去
        return setting;
    }

    @Override
    public void driverOffLine() {
        String openId = StpUtil.getExtra("openId").toString();
        Driver one = super.getOne(new LambdaQueryWrapper<Driver>().eq(Driver::getOpenId, openId));
        String key = String.format(CacheConstants.KEY_DRIVER_ONLINE_SETTING, one.getId());
        redisTemplate.delete(key);
    }

    @Override
    public void geo(GeoRo geoRo) {
        //获取当前登录的司机id
        String openId = StpUtil.getExtra("openId").toString();
        Driver one = super.getOne(new LambdaQueryWrapper<Driver>().eq(Driver::getOpenId, openId));
        //获取小程序 提交的坐标
        Point point = new Point(Double.valueOf(geoRo.getLongitude()),Double.valueOf(geoRo.getLatitude()));
        //将坐标缓存到geo里面
        Long add = redisTemplate.opsForGeo().add(CacheConstants.KEY_DRIVER_GEO, point, one.getId());//处理地理位置的
        //判断是否添加成功
        if(add == RConst.Num.LONG_1){
            //刷新司机的状态
            String key = String.format(CacheConstants.KEY_DRIVER_ONLINE_SETTING, one.getId());
            redisTemplate.expire(key,RConst.Num.INT_5,TimeUnit.MINUTES);
        }

    }

    // 司机去拉去mq里面的乘客数据
    @Override
    public Object pullOrderForDriver() {
        //司机的ID
        Long loginId = Long.valueOf(StpUtil.getLoginId().toString());

       /* Long loginId =1814829262641958912L;*/
        try {
            //订阅消息队列，指定topic
            //Constants.MQ.TOPIC_ORDER+":"+String.format(Constants.MQ.TAGS_ORDER_DRIVER,driverId);
            Set<MessageQueue> messageQueues = pullConsumer.fetchSubscribeMessageQueues(MQconstans.PUSH_ORDER_TO_DRIVER_TOPIC);
            //封装结果
            List<PushOrder> result = new ArrayList<>();
            for (MessageQueue messageQueue : messageQueues) {
                //通过偏移量来获取消息 ：当前队列的消费位置
                long offset = pullConsumer.fetchConsumeOffset(messageQueue, true);
                //拉取消息，需要指定tags拼接司机ID， 来区分司机:
                String tags = String.format(MQconstans.PUSH_ORDER_TO_DRIVER_TAG, loginId);
                PullResult pullResult = pullConsumer.pull(messageQueue, tags, offset, 32);
                //找到消息
                if (pullResult != null && pullResult.getPullStatus().equals(PullStatus.FOUND)) {
                    //拿到消息列表
                    List<MessageExt> messageExtList = pullResult.getMsgFoundList();
                    if(messageExtList == null || messageExtList.size() == 0)continue;
                    for (MessageExt messageExt : messageExtList) {
                        //拿到消息内容，转换为订单对象
                        String message = new String(messageExt.getBody(), StandardCharsets.UTF_8);
                        PushOrder pushOrder = JSON.parseObject(message, PushOrder.class);
                        //添加到结果列表
                        result.add(pushOrder);
                        log.info("获取订单消息 {}",pushOrder);
                    }
                }
                if(pullResult != null){
                    //重要：修改消息的消费位置，如果位置不后移，消息会一直被消费
                    pullConsumer.updateConsumeOffset(messageQueue,pullResult.getNextBeginOffset());
                }
            }
            return result;
        } catch (Exception e) {
            throw new GlobalException("订单拉取失败");
        }
    }


    private static LoginRo buildLoginRo(RegisterDto registerDto,Long id) {
        LoginRo loginRo = new LoginRo();
        loginRo.setId(id);
        loginRo.setPassword("123456");//todo
        loginRo.setType(RConst.Num.INT_1);
        loginRo.setOpenId(registerDto.getOpenid());
        loginRo.setUsername(NameUtil.getName());//todo
        loginRo.setAdmin(false);
        return loginRo;
    }

    private Long initDriver(RegisterDto registerDto) {
        //主表
        //雪花算法生成一个司机id
        Long driverId = IdUtil.createSnowflake(RConst.Num.INT_1, RConst.Num.INT_1).nextId();
        Driver driver = new Driver()
                .setId(driverId)
                .setCreateTime(new Date())
                .setOpenId(registerDto.getOpenid());
        super.save(driver);
        //合同表的新增
        DriverAggrement driverAggrement = new DriverAggrement();
        driverAggrement.setId(IdUtil.createSnowflake(RConst.Num.INT_1, RConst.Num.INT_1).nextId());
        driverAggrement.setDriverId(driverId);
        driverAggrement.setStatus(RConst.Num.INT_0);
        driverAggrement.setCreateTime(new Date());
        driverAggrementService.save(driverAggrement);
        //当前司机的统计表
        DriverSummary driverSummary = new DriverSummary();
        driverSummary.setId(driverId);
        driverSummaryService.save(driverSummary);
        return driverId;
    }
}
